package org.jeecg.modules.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.json.JsonObjectDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.netty.handler.TcpRequestHandler;
import org.jeecg.modules.netty.handler.v1.ByteToStringDecoder;
import org.jeecg.modules.netty.handler.v1.JsonDataHandler;
import org.jeecg.modules.netty.handler.v1.JsonStrToByteEncoder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;

@Slf4j
@Component
public class NettyCloudBoxRunner implements ApplicationRunner, ApplicationListener<ContextClosedEvent>{

    @Value("${netty.cloudBox.port}")
    private int port;

    @Value("${netty.cloudBox.ip}")
    private String ip;

    @Value("${netty.cloudBox.max-frame-size}")
    private long maxFrameSize;

    private Thread cloudBoxT;

    private Channel serverChannel;

    public void run(ApplicationArguments args){
        start();
    }

    private void start(){
        stopThread();
        cloudBoxT = new Thread(null,new CloudBoxRunner(),"CloudBox 监听服务");
        cloudBoxT.start();
    }

    public void onApplicationEvent(ContextClosedEvent event) {
        if (this.serverChannel != null) {
            this.serverChannel.close();
        }
        stopThread();
        log.info("cloudBox协议Socket 服务停止");

    }

    private void stopThread(){
        if(cloudBoxT==null){
            return;
        }
        if(cloudBoxT.isAlive()){
            cloudBoxT.interrupt();
        }
        cloudBoxT = null;
    }


    class CloudBoxRunner implements Runnable{


        @Override
        public void run() {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            try {
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap.group(bossGroup, workerGroup);
                serverBootstrap.channel(NioServerSocketChannel.class);
                serverBootstrap.localAddress(new InetSocketAddress(ip, port));
                serverBootstrap.option(ChannelOption.SO_BACKLOG, 128)
                        .childOption(ChannelOption.SO_KEEPALIVE, true);

                serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();

                        pipeline.addLast(new TcpRequestHandler())
                                .addLast(new LoggingHandler(LogLevel.INFO))
                                //v1协议
                                .addLast(new JsonObjectDecoder())
                                .addLast(new ByteToStringDecoder())
                                .addLast(new JsonStrToByteEncoder())
                                .addLast(new JsonDataHandler())
                        ;
                    }
                });
                Channel channel = serverBootstrap.bind().sync().channel();
                serverChannel = channel;
                log.info("cloudBox协议Socket 服务启动，ip={},port={}", ip, port);

                channel.closeFuture().sync();
            } catch (InterruptedException e) {
                log.error(e.getMessage(),e);
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }

}
